/*
 * 英才汇硕信息科技有限公司 拥有本软件版权 2021 并保留所有权利。
 * Copyright 2021, YCHS Information&Science Techology Co.,Ltd,
 * All right reserved.
 */
package com.ychs.lawyerback.service.impl;



import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ychs.lawyerback.common.Constant;
import com.ychs.lawyerback.common.ResultCode;
import com.ychs.lawyerback.dto.LoginReqDTO;
import com.ychs.lawyerback.dto.UserOptDTO;
import com.ychs.lawyerback.dto.UserQueryDTO;
import com.ychs.lawyerback.exception.BussinessException;
import com.ychs.lawyerback.mapper.MenuMapper;
import com.ychs.lawyerback.mapper.UserMapper;
import com.ychs.lawyerback.pojo.UserEntity;
import com.ychs.lawyerback.service.UserService;
import com.ychs.lawyerback.util.JWTUtil;
import com.ychs.lawyerback.vo.LoginUserVo;
import com.ychs.lawyerback.vo.UserQuseyVo;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;


/**
 * @author mayujing
 * @version 1.0
 */
@Service // 标记这是业务逻辑层组件
public class UserServiceImpl implements UserService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ObjectMapper objectMapper;//把对象转化成json格式的对象或使用Hutool工具类

    @Autowired
    private MenuMapper menuMapper;

   @Autowired  // 自动注入UserMapper（数据库操作）
   private UserMapper userMapper;

   @Autowired  // 自动注入密码加密器
   private PasswordEncoder passwordEncoder;

   @Autowired  // 自动注入JWT工具类
   private JWTUtil jwtUtil;
    @Override
    public Map<String, Object> login(LoginReqDTO loginReqDTO) throws JsonProcessingException {
        //1、通过用户名查询用户信息
        UserEntity userEntity = userMapper.getUserByUsername(loginReqDTO.getUsername());
        if (userEntity == null) {
//            throw new RuntimeException("用户名不存在"); // 后续会统一处理异常
            throw new BussinessException(ResultCode.LOGIN_USERNAME_ERROR);//抛出 自定义的异常
        }
        //2、密码匹配和判断，校验密码（前端传的明文 vs 数据库存的密文）
        boolean res = passwordEncoder.matches(
                loginReqDTO.getPassword(),  // 前端明文密码
                userEntity.getPassword()); // 数据库密文密码
        if (!res) {
            throw new BussinessException(ResultCode.LOGIN_PWD_ERROR);//抛出 自定义的异常
        }
        //3、生成token（JWT令牌）
        //claims 是 JWT 规范中的概念，用于携带非敏感的用户信息或业务数据（如用户名、角色、权限等）。
        Map<String, Object> claims = new HashMap<>();//创建一个HashMap集合，用于存储键值对形式的附加信息（JWT中称为“载荷”或“声明”）

        claims.put("username", userEntity.getUsername());//令牌中携带用户名，像claims中添加一条键值对：key自己定义。
        // value为userEntity.getUsername()，从数据库查询到的用户实体中的用户名（如登录用户的用户名）

        //将claims中的信息嵌入到生成的JWT令牌中
        String token = jwtUtil.generateToken(userEntity.getId(), claims);

        //4、获取权限信息
        List<String> permissions = menuMapper.getPermissions(userEntity.getRoleId());

        //5、将userEntity对象中的属性值快速复制到loginUserVo对象中
        LoginUserVo loginUserVo = new LoginUserVo();
        BeanUtils.copyProperties(userEntity,loginUserVo);
        //6、将生成的 Token 和用户权限信息存入loginUserVo对象，然后将该对象存入 Redis 缓存
        // 给登录用户视图对象设置令牌
        loginUserVo.setToken(token);
//        将查询到的用户权限列表（如 “案件管理”“客户管理” 等操作权限）存入对象，用于后续接口的权限校验；
        loginUserVo.setPermission(permissions);
        //将用户的登录状态信息存储到 Redis 中
        //Hutool工具类
        /**
         * 总只做了三件事：
         * Constant.TOKEN_PREFIX+userEntity.getId() 确定redis的key
         * JSONUtil.toJsonStr(loginUserVo)：是将loginUserVo对象转换为字符串（包括用户基本信息、token、权限列表等）
         *                                  因为redis只能存储字符串类型，需要序列化才能存储，后续验证时再将JSON字符串反序列化为对象使用
         * Constant.TOKEN_TIME和TimeUnit.SECONDS表示这个键值对的过期时间
         */
        redisTemplate.opsForValue().set(Constant.TOKEN_PREFIX+userEntity.getId(),// Redis的key（如：Login:Token:123）
//                objectMapper.writeValueAsString(loginUserVo), // Redis的value（序列化后的字符串）
                JSONUtil.toJsonStr(loginUserVo),//Hutool工具类 Redis的value（序列化后的字符串）
                Constant.TOKEN_TIME,// 过期时间，也就是时间数值，仅表示一个数字
                TimeUnit.SECONDS);// 时间单位（秒），用来标记这个数值是时间
        /**
         * 存这些消息是为了支持“强制登出”和“单设备登录”等功能。
         */


        // 4. 封装返回数据（用户信息+令牌）
        Map<String, Object> map = new HashMap<>();
        map.put("token",token);
        map.put("username",userEntity.getUsername()); // 可以根据需要返回更多信息
        map.put("perms",permissions);
        map.put("id",userEntity.getId());
        map.put("roleId", userEntity.getRoleId()); // 直接返回角色ID（推荐）
        return map;//这里直接返回map，用与后续controller层调用
    }

    @Override
    public Map<String, Object> getUsersByCondition(UserQueryDTO userQueryDTO) {
        List<UserQuseyVo> users = userMapper.getUsersByCondition(userQueryDTO);
        int total = userMapper.getCountByCondition(userQueryDTO);
        Map<String, Object> map = new HashMap<>();
        map.put("list", users);
        map.put("total", total);
        return map;
    }

    @Override
    @Transactional
    public long addUser(UserOptDTO userOptDTO) {
        UserEntity userEntity=new UserEntity();
        BeanUtils.copyProperties(userOptDTO,userEntity);
        userEntity.setPassword(passwordEncoder.encode(Constant.DEFAULT_PWD));
        //登录的用户 createBy，之后写
//        int res = userMapper.addUser(userEntity);
//        return res;

        userMapper.addUser(userEntity); // 插入后，userEntity.id 已被回填
        return userEntity.getId(); // 返回数据库生成的真实用户ID
    }

    @Override
    @Transactional
    public int editUser(UserOptDTO userOptDTO) {
        UserEntity userEntity=new UserEntity();
        BeanUtils.copyProperties(userOptDTO,userEntity);
//        userEntity.setPassword(passwordEncoder.encode(Constant.DEFAULT_PWD));
        int res = userMapper.editUser(userEntity);
        return res;
    }

    @Override
    public boolean existsByUsername(String username) {
        int count = userMapper.countByUsername(username);
        // 若 count > 0，说明存在；否则不存在
        return count > 0;
    }

    @Override
    @Transactional
    public int deleteUser(List<Long> ids) {

        return userMapper.deleteUser(ids);
    }
}
